﻿#pragma once
#include <stdio.h>
#include <signal.h>
#include <atomic>
#include <string>
#include <thread>
#include <iostream>
#include <vector>
#include <mutex>
#include <queue>

#include "base_util/utils.h"

namespace stream {

// 算法运行策略
enum AlgoStrategyMode {
  STRATEGY_NONE = -1,         // 
  STRATEGY_FULLSPEED = 0,     // 全速分析
  STRATEGY_ROTATION = 1,      // 算力轮询
  STRATEGY_FIXTIME = 2,       // 定时抽帧
};

struct StreamPullerInfo {
  StreamPullerInfo(): enType(0), vdecChn(-1), oriWidth(-1), oriHeight(-1) {}
  int oriWidth;
  int oriHeight;
  int useWidth;
  int useHeight;
  int vdecChn;      // 解码通道
  std::string channelId;
  int enType;
  std::string streamAddress;
  std::string transferType;

};

struct StreamPusherInfo {
  std::string formatName;
  std::string codecProfile;
  int fps;
  int bitrate;        // Mbps
  std::string streamAddress;
  int dstWidth;
  int dstHeight;

  int vEncChn;
  int enType;     // encoder_type
};

struct OSDDrawInfo {
  OSDDrawInfo() {}
  OSDDrawInfo(int x, int y, int w, int h, float s):
      x(x), y(y), w(w), h(h), score(s) {}

  int x;
  int y;
  int w;
  int h;
  float score;
  std::vector<std::string> texts;
};

struct StreamOsdBaseInfo {
  int dstWidth;
  int dstHeight;
  int boxThick; 
};




enum ImageBlobMode {
  ImageBlobMode_NONE = -1,
  ImageBlobMode_YUV = 0,
  ImageBlobMode_YUV_NV12 = 0,
  ImageBlobMode_YUV_I420 = 1,
  ImageBlobMode_BGR = 2,
};

/*
data_mode
0: horizon mode
1: rk3588 mode onnx模式与rk3588模式相同 共用 ImageBlobMode_BGR
*/
class ImageBlob {
 public:
  ImageBlob(): data_mode(ImageBlobMode_NONE), yuv_size(0), source_id(-1), rec_flag(-1), infer_id(-1) {}
  ImageBlob(int cur_mode, int data_size=0): data_mode(cur_mode), 
    yuv_size(data_size), source_id(-1) {
    // yuv data 3840 * 2160 * 3 / 2
    if (data_mode == ImageBlobMode_YUV_NV12 || data_mode == ImageBlobMode_YUV_I420) { yuv.resize(yuv_size); }
    rec_flag = -1;
    infer_id = -1;
  }
  ~ImageBlob() {}
  ImageBlob(const ImageBlob& blob) {
    data_mode = blob.data_mode;
    // ImageBlobMode_NONE 模式时，两种数据都拷贝
    if (data_mode <= ImageBlobMode_YUV_I420) { yuv = blob.yuv; yuv_size = blob.yuv_size; }
    if (data_mode == ImageBlobMode_BGR || data_mode == ImageBlobMode_NONE) { img = blob.img.clone(); }
    imgs = blob.imgs;

    model_id = blob.model_id;
    ori_im_shape = blob.ori_im_shape;
    // cnt = blob.cnt;
    source_id = blob.source_id;
    id_string = blob.id_string;
    infer_id = blob.infer_id;
    // 数据拷贝时给一个未识别的标志
    rec_flag = 0;
  }
  ImageBlob& operator=(const ImageBlob& blob) {
    if (this == &blob) { return *this; }
    data_mode = blob.data_mode;

    if (data_mode <= ImageBlobMode_YUV_I420) { yuv = blob.yuv; yuv_size = blob.yuv_size; }
    if (data_mode == ImageBlobMode_BGR || data_mode == ImageBlobMode_NONE) { img = blob.img.clone(); }
    imgs = blob.imgs;
    
    // 有条件的覆盖
    if (model_id.empty()) {model_id = blob.model_id;}
    ori_im_shape = blob.ori_im_shape;
    // cnt = blob.cnt;
    source_id = blob.source_id;
    id_string = blob.id_string;
    infer_id = blob.infer_id;
    // 数据拷贝时给一个未识别的标志
    rec_flag = 0;
    return *this;
  }
  void clear() {
    yuv.clear();
    deal_order.clear();
    im_shape_record.clear();
  }
  std::vector<int> ori_im_shape = std::vector<int>(2);
  std::vector<int> new_im_shape = std::vector<int>(2);
  // Image height and width record
  std::vector<std::vector<int>> im_shape_record;
  // Deal order
  std::vector<std::string> deal_order;
  // Resize scale
  float scale = 1.0;
  // Buffer for image data after preprocessing
  std::vector<float> im_vec_data;

  // 图片识别使用
  cv::Mat img;
  // 视频识别使用
  std::vector<cv::Mat> imgs;
  std::vector<char> yuv;
  int32_t yuv_size;
  int data_mode;
  // uint8_t cnt;

  std::string model_id;  // 当前需要调用的模型 
  
  // 推理id 由推理框架设置
  int infer_id;

  // 此变量不能被拷贝构造函数覆盖 // 用于判断当前数据有没有正在被识别
  // 0 未识别 1 正在识别 2 识别完成
  std::atomic_int rec_flag;

  // 上层调用者维护和使用变量
  // 数据包的id 用于区分每一块数据包 由上层调用者维护和使用
  // 数据来源
  // 数据源id 由上层设置
  int source_id;
  std::string id_string;
};


};